﻿#include "qbcihdrenderstaticfunc.h"

QBciHDRenderStaticFunc *QBciHDRenderStaticFunc::Instance = NULL;

QBciHDRenderStaticFunc *QBciHDRenderStaticFunc::getinstance() {
  if (Instance == NULL) {
    Instance = new QBciHDRenderStaticFunc();
  }
  return Instance;
}

QBciHDRenderStaticFunc::QBciHDRenderStaticFunc() {
  QString portName = "COM6";
  setPort(portName);
  std::cout << "Open Serial:" + portName.toStdString() << std::endl;

  allBlockInit();
  connect(this, &QBciHDRenderStaticFunc::newConstruction, this,
          &QBciHDRenderStaticFunc::write);
}

QBciHDRenderStaticFunc::~QBciHDRenderStaticFunc() { resetAllBlock(); }

void QBciHDRenderStaticFunc::setBlockEnable(const int &ID, const bool &enable) {
  ConfigList[ID].Enable = enable;
}

void QBciHDRenderStaticFunc::setBlockFreq(const int &ID, const double &freq) {
  ConfigList[ID].Freq = freq;
}

void QBciHDRenderStaticFunc::setBlockDuti(const int &ID, const double &duti) {
  ConfigList[ID].Duti = duti;
}

void QBciHDRenderStaticFunc::setBlockLabel(const int &ID,
                                           const QString &label) {
  ConfigList[ID].Label = label;
}

void QBciHDRenderStaticFunc::setBlockFlick(const int &ID, const bool &flick) {
  ConfigList[ID].Flick = flick;
}

void QBciHDRenderStaticFunc::setBlock(const int &ID, const bool &enable,
                                      const double &freq, const double &duti,
                                      const QString &label) {
  setBlockEnable(ID, enable);
  setBlockFreq(ID, freq);
  setBlockDuti(ID, duti);
  setBlockLabel(ID, label);
}

void QBciHDRenderStaticFunc::allBlockInit() {
  for (int iB = 0; iB < BlockNum; ++iB) {
    BlockConfig config;
    config.ID = iB;
    ConfigList << config;
  }

  setBlock(0, true, 0, 0.5, "stop");
  setBlock(1, true, 0, 0.5, "whistle");
  setBlock(2, true, 0, 0.5, "none");
  setBlockFlick(2, false);
  setBlock(3, true, 0, 0.5, "left");
  setBlock(4, true, 0, 0.5, "none");
  setBlockFlick(4, false);
  setBlock(5, true, 0, 0.5, "front");
  setBlock(6, true, 0, 0.5, "back");
  setBlock(7, true, 0, 0.5, "none");
  setBlockFlick(7, false);
  setBlock(8, true, 0, 0.5, "right");
  setBlock(9, true, 0, 0.5, "none");
  setBlockFlick(9, false);
  setBlock(10, true, 0, 0.5, "speed_up");
  setBlock(11, true, 0, 0.5, "speed_down");
  setBlock(12, true, 0, 0.5, "none");
  setBlockFlick(12, false);
}

void QBciHDRenderStaticFunc::resetAllBlock() {
  std::cout << "Reset All Block" << std::endl;
  QList<bool> save;
  for (int iB = 0; iB < BlockNum; ++iB) {
    save.append(ConfigList[iB].Flick);
    ConfigList[iB].Flick = false;
  }
  getConstruction();
  for (int iB = 0; iB < BlockNum; ++iB) {
    ConfigList[iB].Flick = save.at(iB);
  }
}

void QBciHDRenderStaticFunc::setWaveType(QBciRender::WaveType wave) {
  Wave = wave;
}

int QBciHDRenderStaticFunc::EnableWaveCount = 0;
int QBciHDRenderStaticFunc::HDRenderCount = 0;

void QBciHDRenderStaticFunc::setEnableWave(const int &ID, const bool &flag) {
  setBlockFlick(ID, flag);
  EnableWaveCount++;
  if (EnableWaveCount == HDRenderCount) {
    getConstruction();
    EnableWaveCount = 0;
  }
}

QByteArray QBciHDRenderStaticFunc::getConstruction(){

    char header = 58;
    QByteArray construction;
    construction.append(header);

    auto f = [=](const short &u16, char &u8H, char &u8L) {
      short maskLow = 0xFF, maskHigh = 0xFF00;
      u8H = static_cast<char>((maskHigh & u16) >> 8);
      u8L = static_cast<char>(maskLow & u16);
    };

    for (int iB = 0; iB < BlockNum; ++iB) {
      const BlockConfig &config = ConfigList.at(iB);
      short freq = static_cast<short>(config.Freq * 100);
      char freqHigh;
      char freqLow;
      f(freq, freqHigh, freqLow);

      char ctlBit = 0;
      if (!config.Enable) {
        ctlBit += 8;
      }
      if (config.Flick) {
        ctlBit += 1;
      } else {
        ctlBit += 2;
      }

      short duti = static_cast<short>(config.Duti * 1000);
      char dutiHigh;
      char dutiLow;
      f(duti, dutiHigh, dutiLow);

      construction.append(freqHigh)
          .append(freqLow)
          .append(ctlBit)
          .append(dutiHigh)
          .append(dutiLow);
    }

    switch (Wave) {
    case QBciRender::square:
      construction.append(char(85));
      for (int iB = 0; iB < BlockNum; ++iB) {
        construction.append(char(0)).append(char(0));
      }
      break;
    case QBciRender::sin:
      construction.append(char(170));
      for (int iB = 0; iB < BlockNum; ++iB) {
        short freq = static_cast<short>(ConfigList.at(iB).Freq * 85.8993);
        char freqHigh;
        char freqLow;
        f(freq, freqHigh, freqLow);
        construction.append(freqHigh).append(freqLow);
      }
      break;
    }

    construction.append(char(59));

    emit newConstruction(construction);
    return construction;
  }

void QBciHDRenderStaticFunc::setPort(QString portname) {
  serial = new QSerialPort;
  serial->setPortName(portname);
  serial->setBaudRate(QSerialPort::Baud9600);
  serial->setParity(QSerialPort::NoParity);
  serial->setDataBits(QSerialPort::Data8);
  serial->setStopBits(QSerialPort::OneStop);
  serial->setFlowControl(QSerialPort::NoFlowControl);

  if (serial->open(QIODevice::ReadWrite)) {
    QLogger::Info("UART::Serial opened!");
    qDebug() << "Serial opened";
  } else {
    QLogger::Error("UART::Serial open failed!");
    qDebug() << "Serial failed";
  }
}

void QBciHDRenderStaticFunc::write(const QByteArray &mesg) {
  serial->write(mesg);
  serial->waitForBytesWritten();
  qDebug() << "Serial Writed";
}
